package com.yuzhihao.writejvm.field;

import com.yuzhihao.writejvm.attributes.Attributes;
import com.yuzhihao.writejvm.clazz.ClassInfo;
import com.yuzhihao.writejvm.constant.ConstantUtf8Info;
import com.yuzhihao.writejvm.format.ClassFormatEnum;
import com.yuzhihao.writejvm.format.PrintFormat;
import com.yuzhihao.writejvm.read.Parse;
import com.yuzhihao.writejvm.read.TypeFatory;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.log4j.Log4j2;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Each field is described by a field_info structure.
 *
 * <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5">jvmdoc</a>
 *
 * @author yzh
 * @since 2021年12月09日15:09:04
 */
@Data
@Log4j2
@EqualsAndHashCode(callSuper = true)
public class FieldInfo extends Fields {

    private ClassFormatEnum cfe_f = ClassFormatEnum.fields;
    private int access_flags_u2 = 2;
    private int name_index_u2 = 2;
    private int descriptor_index_u2 = 2;
    private int attributes_count_u2 = 2;

    private int access_flags;

    private int name_index;

    private int descriptor_index;

    private int attributes_count;

    private List<Attributes> attributes = new ArrayList<>();


    @Override
    public void parse(DataInputStream dis, ClassInfo ci) {
        this.setCi(ci);
        try {
            this.access_flags = Parse.byteToInt(this.access_flags_u2, dis);
            this.name_index = Parse.byteToInt(this.name_index_u2, dis);
            this.descriptor_index = Parse.byteToInt(this.descriptor_index_u2, dis);
            this.attributes_count = Parse.byteToInt(this.attributes_count_u2, dis);
        } catch (IOException e) {
            log.error(e);
        }

        this.out(dis,ci);
    }

    public void out(DataInputStream dis,ClassInfo ci){
        if (this.attributes_count > 0){
            Attributes a = new Attributes(this.attributes_count);
            a.parse(dis,ci);
            this.setAttributes(a.getAttributes());
        }
    }

    public String print(ClassInfo ci) {
        StringBuilder builder = new StringBuilder();
        builder.append(PrintFormat.EMPTY);
        List<TypeFatory.Access> accesses = TypeFatory.access_flags(this.access_flags);
        for (TypeFatory.Access access : accesses) {
            builder.append(access.getName()).append(PrintFormat.EMPTY);
        }

        ConstantUtf8Info ni = (ConstantUtf8Info) ci.getCp_info().getPools().get(String.valueOf(this.name_index));
        ConstantUtf8Info di = (ConstantUtf8Info) ci.getCp_info().getPools().get(String.valueOf(this.descriptor_index));

        builder.append(TypeFatory.field_type(di.getConstant()))
                .append(PrintFormat.EMPTY)
                .append(ni.getConstant())
                .append(PrintFormat.SEMICOLON)
                .append(System.lineSeparator());
        builder.append(PrintFormat.MEMPTY)
                .append("descriptor")
                .append(PrintFormat.COLON)
                .append(di.getConstant())
                .append(System.lineSeparator());
        builder.append(PrintFormat.MEMPTY).append("flags").append(PrintFormat.COLON);
        for (TypeFatory.Access access : accesses) {
            builder.append(access.getFname()).append(",");
        }
        builder.delete(builder.length()-1,builder.length());
        builder.append(System.lineSeparator());
        builder.append(System.lineSeparator());

        return builder.toString();
    }

}
